﻿// Copyright (c) 2012-2013 fancidev
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;

namespace Util.Media
{
    public class BitmapHelper
    {
#if false
        /// <summary>
        /// Creates a Bitmap of the given size and places an existing image
        /// at the center of it and proportionally scaled if too large.
        /// </summary>
        /// <param name="image">The existing image.</param>
        /// <param name="size">The new size of the image.</param>
        /// <returns>A new bitmap.</returns>
        public static Bitmap CenterImage(Image image, Size size)
        {
            // Fit the source image into the target image, keeping scale.
            Rectangle bounds = new Rectangle(0, 0, size.Width, size.Height);
            Size sz = image.Size;
            if (sz.Width > bounds.Width)
            {
                sz.Height = sz.Height * bounds.Width / sz.Width;
                sz.Width = bounds.Width;
            }
            if (sz.Height > bounds.Height)
            {
                sz.Width = sz.Width * bounds.Height / sz.Height;
                sz.Height = bounds.Height;
            }
            bounds.X += (bounds.Width - sz.Width) / 2;
            bounds.Y += (bounds.Height - sz.Height) / 2;
            bounds.Width = sz.Width;
            bounds.Height = sz.Height;

            // Create a new bitmap of the desired size.
            Bitmap newBitmap = new Bitmap(size.Width, size.Height,
                System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            using (Graphics g = Graphics.FromImage(newBitmap))
            {
                g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
                g.DrawImage(image, bounds);
            }
            return newBitmap;
        }

        public static int GetAverageIntensity(Bitmap bmp)
        {
            var bmpData = bmp.LockBits(
                new Rectangle(0, 0, bmp.Width, bmp.Height),
                System.Drawing.Imaging.ImageLockMode.ReadOnly,
                System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            IntPtr bmpPtr = bmpData.Scan0;
            int[] argb = new int[bmp.Width * bmp.Height];
            System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, argb, 0, argb.Length);
            bmp.UnlockBits(bmpData);

            int sumRgb = argb.Select(x =>
                ((x >> 16) & 0xFF) + ((x >> 8) & 0xFF) + (x & 0xFF)
                ).Sum();
            return sumRgb / (3 * bmp.Width * bmp.Height);
        }

        public static void CopyImageData(Bitmap src, Bitmap dest)
        {
            int width = src.Width;
            int height = src.Height;
            var bmpData1 = src.LockBits(
                new Rectangle(0, 0, width, height),
                System.Drawing.Imaging.ImageLockMode.ReadOnly,
                System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            byte[] data = new byte[height * bmpData1.Stride];
            System.Runtime.InteropServices.Marshal.Copy(bmpData1.Scan0, data, 0, data.Length);
            src.UnlockBits(bmpData1);

            var bmpData2 = dest.LockBits(
                new Rectangle(0, 0, width, height),
                System.Drawing.Imaging.ImageLockMode.WriteOnly,
                System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            System.Runtime.InteropServices.Marshal.Copy(data, 0, bmpData2.Scan0, data.Length);
            dest.UnlockBits(bmpData2);
        }

        private static void MultiplyAlpha(Bitmap src, Bitmap dest)
        {
            if (src.Size != dest.Size)
                throw new ArgumentException("Source and destination images must have the same size.");

            int width = src.Width;
            int height = src.Height;

            //if (bmp.PixelFormat != PixelFormat.Format32bppArgb &&
            //    bmp.PixelFormat != PixelFormat.Format32bppPArgb)
            //    throw new ArgumentException("Expect 32-bpp pixel format with alpha channel.");

            BitmapData srcData = src.LockBits(
                new Rectangle(0, 0, width, height),
                System.Drawing.Imaging.ImageLockMode.ReadOnly,
                src.PixelFormat);
            BitmapData destData = dest.LockBits(
                new Rectangle(0, 0, width, height),
                System.Drawing.Imaging.ImageLockMode.WriteOnly,
                dest.PixelFormat);

            IntPtr srcPtr = srcData.Scan0;
            IntPtr destPtr = destData.Scan0;

            int[] scanline = new int[width];
            for (int y = 0; y < height; y++)
            {
                Marshal.Copy(srcPtr, scanline, 0, scanline.Length);
                for (int x = 0; x < scanline.Length; x++)
                {
                    int c = scanline[x];
                    int a = (c >> 24) & 0xFF;
                    int r = ((c >> 16) & 0xFF) * a / 255;
                    int g = ((c >> 8) & 0xFF) * a / 255;
                    int b = ((c >> 0) & 0xFF) * a / 255;
                    scanline[x] = (a << 24) | (r << 16) | (g << 8) | (b << 0);
                }
                Marshal.Copy(scanline, 0, destPtr, scanline.Length);
                srcPtr += srcData.Stride;
                destPtr += destData.Stride;
            }

            dest.UnlockBits(destData);
            src.UnlockBits(srcData);
        }

        private static void MultiplyAlpha(Bitmap bmp)
        {
            if (bmp.PixelFormat != PixelFormat.Format32bppArgb &&
                bmp.PixelFormat != PixelFormat.Format32bppPArgb)
                throw new ArgumentException("Expect 32-bpp pixel format with alpha channel.");

            var bmpData = bmp.LockBits(
                new Rectangle(0, 0, bmp.Width, bmp.Height),
                System.Drawing.Imaging.ImageLockMode.ReadWrite,
                bmp.PixelFormat);
            IntPtr bmpPtr = bmpData.Scan0;

            int[] scanline = new int[bmp.Width];
            for (int y = 0; y < bmp.Height; y++)
            {
                Marshal.Copy(bmpPtr, scanline, 0, scanline.Length);
                for (int x = 0; x < scanline.Length; x++)
                {
                    int c = scanline[x];
                    int a = (c >> 24) & 0xFF;
                    int r = ((c >> 16) & 0xFF) * a / 255;
                    int g = ((c >> 8) & 0xFF) * a / 255;
                    int b = ((c >> 0) & 0xFF) * a / 255;
                    scanline[x] = (a << 24) | (r << 16) | (g << 8) | (b << 0);
                }
                Marshal.Copy(scanline, 0, bmpPtr, scanline.Length);
                bmpPtr += bmpData.Stride;
            }

            bmp.UnlockBits(bmpData);
        }
#endif
    }
}
